﻿/*
 * XapExplorer, global object/singleton like
 * manages applications load, run, stop, activate,...
 * 
 * created by: asida@centrum.cz
 * 
 * initial implementation: 6.12.2011
 * last updated:
 */
using System;
using System.Windows;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.Reflection;
using System.Runtime.CompilerServices;

using uhul.Controls;

using System.Diagnostics;



namespace uhul
{

    public partial class XapExplorer
    {



        public class CommandStack : ObservableCollection<string>
        {

            private int waitingCmdCounter;
            private int currentCmd;
            private int lastWaitCmdIndex;

            private object lockKey;

            public CommandStack()
            {
                waitingCmdCounter = 0;
                currentCmd = 0;
                lastWaitCmdIndex = 0;
                lockKey = new object();
            }

            //// force event override to let step through delegates then..
            //public override event NotifyCollectionChangedEventHandler CollectionChanged;

            //event NotifyCollectionChangedEventHandler CollectionChanged
            //{
            //  add { base.CollectionChanged += value; }
            //  remove { base.CollectionChanged -= value; }
            //}

            //protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
            //{
            //  NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
            //  if (eventHandler == null)
            //    return;

            //  Delegate[] delegates = eventHandler.GetInvocationList();
            //}


            protected override void InsertItem(int index, string item)
            {
                InsertItemWithAsync(index, item, null, -1);
            }




            [MethodImpl(MethodImplOptions.Synchronized)]
            private void InsertItemWithAsync(int index, string item, DispatcherTimer timer, int cmdOrderId)
            {

                Debug.WriteLine("enter InsertItemWithAsync cmdOrderId={0}", cmdOrderId);

                int tmpOrderId;

                if (timer != null) //here always cmdOrderId > -1
                {
                    Debug.WriteLine("timer != null");
                    //previous waiting/async command call
                    timer.Stop();

                    waitingCmdCounter--;
                    tmpOrderId = cmdOrderId;
                }
                else if (waitingCmdCounter == 0) //here always cmdOrderId == -1
                {
                    Debug.WriteLine("tmpOrderId = 0");
                    //no waiting command (or one in process in recurency), try execute now
                    tmpOrderId = 0;
                    lastWaitCmdIndex = 0;
                }
                else //if (currentCmd == 0) //here always cmdOrderId == -1
                {
                    Debug.WriteLine("tmpOrderId = lastWaitCmdIndex++");
                    //there is (first) awaiting command in queue, this cmd must wait
                    lastWaitCmdIndex++;
                    tmpOrderId = lastWaitCmdIndex;
                }
                //else
                //{
                //    Debug.WriteLine("tmpOrderId = waitingCmdCounter + 1");
                //    //there are awaiting commands in queue, this cmd must wait
                //    tmpOrderId = waitingCmdCounter + 1;
                //}

                Debug.WriteLine("waitingCmdCounter={0}, tmpOrderId={1}, currentCmd={2}, lastWaitCmdIndex={3}", waitingCmdCounter, tmpOrderId, currentCmd, lastWaitCmdIndex);

                //InteractiveApp appToStop = null;
                //Command c = Command.Parse(item);

                //if (XapExplorer._appValidator.ContainsKey(c.TargetApplicationName))
                //  appToStop = XapExplorer._appValidator[c.TargetApplicationName];

                if (tmpOrderId == currentCmd) //process only command that is in right order
                    try
                    {
                        Debug.WriteLine("base.InsertItem");
                        //int prevCmd = currentCmd; //save previous cmd
                        //int prevWaitingCmdCounter = waitingCmdCounter;
                        base.InsertItem(index, item);

                        if (lastWaitCmdIndex > currentCmd)
                            currentCmd++;


                        //if (waitingCmdCounter > 0 && cmdOrderId > -1 //increment only when queued command and not reset stack
                        //    && prevCmd == currentCmd && prevWaitingCmdCounter > 0) 
                        //    currentCmd++;

                        else
                            currentCmd = 0;

                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("catch _waitCmd");
                        //cant process now, wait this command
                        _waitCmd(index, item, tmpOrderId);
                    }

                else //command out of order, wait again...
                {
                    Debug.WriteLine("else _waitCmd");
                    _waitCmd(index, item, tmpOrderId);

                    if (tmpOrderId == 0 && currentCmd > 0) //if restart stack index...
                    {
                        lastWaitCmdIndex = 0; //restart wait command numbering
                        currentCmd = 0; //reset current command
                    }
                }

                Debug.WriteLine("exit InsertItemWithAsync");
                Debug.WriteLine("");

            }




            private void _waitCmd(int index, string item, int cmdOrderId)
            {

                waitingCmdCounter++;

                DispatcherTimer tmp = new DispatcherTimer();

                tmp.Tick +=
                delegate(object s, EventArgs args)
                {
                    InsertItemWithAsync(index, item, tmp, cmdOrderId);
                };

                //tmp.Interval = TimeSpan.FromMilliseconds(200 + (100 * waitingCmdCounter));
                tmp.Interval = TimeSpan.FromMilliseconds(200);
                tmp.Start();

            }




            //protected static void resolveStopApplication(CommandStack instance, InteractiveApp app)
            //{
            //  if (app == null)
            //    return;

            //  object f = typeof(ObservableCollection<string>).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);

            //  foreach (EventInfo ev in instance.GetType().GetEvents())
            //  {
            //    FieldInfo fi = instance.GetType().GetField(ev.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
            //    Delegate del = (Delegate)fi.GetValue(instance);
            //    var list = del.GetInvocationList();
            //    foreach (var d in list)
            //    {
            //      //Console.WriteLine("{0}", d.Method.Name);
            //    }
            //  }

            //  //object o = GetEventHandler(instance, "CollectionChanged");

            //  //EventInfo o = (EventInfo)instance.GetType().GetMember("CollectionChanged", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public).GetValue(0);
            //  EventInfo eventInfo = instance.GetType().GetEvent("CollectionChanged");


            //  MethodInfo getInvocationListMethod = eventInfo.EventHandlerType.GetMethod("GetInvocationList", BindingFlags.Instance | BindingFlags.Public);

            //  object classInstance = Activator.CreateInstance(getInvocationListMethod.DeclaringType, null);
            //  //Delegate[] delegates = (Delegate[])getInvocationListMethod.Invoke(eventInfo.EventHandlerType, null);
            //  object delegates = getInvocationListMethod.Invoke(classInstance, null);

            //  //EventInfo e = base.GetType().GetEvent("CollectionChanged");

            //  //if (eventHandler == null)
            //  //  return;

            //  //Delegate[] delegates = eventHandler.GetInvocationList();
            //  //object registeredApp;

            //  //// Walk thru invocation list
            //  //foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
            //  //{
            //  //  registeredApp = handler.Target;
            //  //  // If the subscriber is a DispatcherObject and different thread
            //  //  if (registeredApp == app)
            //  //    this.CollectionChanged -= handler;

            //  //}
            //}



            //static EventHandler GetEventHandler(object classInstance, string eventName)
            //{
            //  Type classType = classInstance.GetType();
            //  FieldInfo eventField = classType.GetField(eventName, BindingFlags.GetField | BindingFlags.Public | BindingFlags.Instance);

            //  EventHandler eventDelegate = (EventHandler)eventField.GetValue(classInstance);

            //  // eventDelegate will be null if no listeners are attached to the event
            //  if (eventDelegate == null)
            //  {
            //    return null;
            //  }

            //  return eventDelegate;
            //}




            //public static CommandStack Create()
            //{
            //  return new CommandStack();
            //}

        }




    }

}
